{{>partial_header}}
use std::sync::Arc;
use std::borrow::Borrow;
use std::pin::Pin;
#[allow(unused_imports)]
use std::option::Option;

use hyper;
use hyper_util::client::legacy::connect::Connect;
use futures::Future;

use crate::models;
use super::{Error, configuration};
use super::request as __internal_request;

pub struct {{{classname}}}Client<C: Connect>
    where C: Clone + std::marker::Send + Sync + 'static {
    configuration: Arc<configuration::Configuration<C>>,
}

impl<C: Connect> {{{classname}}}Client<C>
    where C: Clone + std::marker::Send + Sync {
    pub fn new(configuration: Arc<configuration::Configuration<C>>) -> {{{classname}}}Client<C> {
        {{{classname}}}Client {
            configuration,
        }
    }
}

pub trait {{{classname}}}: Send + Sync {
{{#operations}}
{{#operation}}
    fn {{{operationId}}}(&self, {{#allParams}}{{{paramName}}}: {{^required}}Option<{{/required}}{{#required}}{{#isNullable}}Option<{{/isNullable}}{{/required}}{{#isString}}{{^isUuid}}&str{{/isUuid}}{{/isString}}{{#isUuid}}&str{{/isUuid}}{{^isString}}{{^isUuid}}{{^isPrimitiveType}}{{^isContainer}}models::{{/isContainer}}{{/isPrimitiveType}}{{{dataType}}}{{/isUuid}}{{/isString}}{{^required}}>{{/required}}{{#required}}{{#isNullable}}>{{/isNullable}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}}) -> Pin<Box<dyn Future<Output = Result<{{^returnType}}(){{/returnType}}{{#returnType}}{{{returnType}}}{{/returnType}}, Error>> + Send>>;
{{/operation}}
{{/operations}}
}

impl<C: Connect>{{{classname}}} for {{{classname}}}Client<C>
    where C: Clone + std::marker::Send + Sync {
 {{#operations}}
 {{#operation}}
    #[allow(unused_mut)]
    fn {{{operationId}}}(&self, {{#allParams}}{{{paramName}}}: {{^required}}Option<{{/required}}{{#required}}{{#isNullable}}Option<{{/isNullable}}{{/required}}{{#isString}}{{^isUuid}}&str{{/isUuid}}{{/isString}}{{#isUuid}}&str{{/isUuid}}{{^isString}}{{^isUuid}}{{^isPrimitiveType}}{{^isContainer}}models::{{/isContainer}}{{/isPrimitiveType}}{{{dataType}}}{{/isUuid}}{{/isString}}{{^required}}>{{/required}}{{#required}}{{#isNullable}}>{{/isNullable}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}}) -> Pin<Box<dyn Future<Output = Result<{{^returnType}}(){{/returnType}}{{#returnType}}{{{.}}}{{/returnType}}, Error>> + Send>> {
        let mut req = __internal_request::Request::new(hyper::Method::{{{httpMethod.toUpperCase}}}, "{{{path}}}".to_string())
        {{#hasAuthMethods}}
        {{#authMethods}}
        {{#isApiKey}}
            .with_auth(__internal_request::Auth::ApiKey(__internal_request::ApiKey{
                in_header: {{#isKeyInHeader}}true{{/isKeyInHeader}}{{^isKeyInHeader}}false{{/isKeyInHeader}},
                in_query: {{#isKeyInQuery}}true{{/isKeyInQuery}}{{^isKeyInQuery}}false{{/isKeyInQuery}},
                param_name: "{{{keyParamName}}}".to_owned(),
            }))
        {{/isApiKey}}
        {{#isBasicBasic}}
            .with_auth(__internal_request::Auth::Basic)
        {{/isBasicBasic}}
        {{#isOAuth}}
            .with_auth(__internal_request::Auth::Oauth)
        {{/isOAuth}}
        {{/authMethods}}
        {{/hasAuthMethods}}
        ;
        {{#queryParams}}
        {{#required}}
        {{^isNullable}}
        req = req.with_query_param("{{{baseName}}}".to_string(), {{{paramName}}}{{#isArray}}.join(","){{/isArray}}.to_string());
        {{/isNullable}}
        {{#isNullable}}
        match {{{paramName}}} {
            Some(param_value) => { req = req.with_query_param("{{{baseName}}}".to_string(), param_value{{#isArray}}.join(","){{/isArray}}.to_string()); },
            None => { req = req.with_query_param("{{{baseName}}}".to_string(), "".to_string()); },
        }
        {{/isNullable}}
        {{/required}}
        {{^required}}
        if let Some(ref s) = {{{paramName}}} {
            {{#isArray}}
            let query_value = s.iter().map(|s| s.to_string()).collect::<Vec<String>>().join(",");
            {{/isArray}}
            {{^isArray}}
            let query_value = match serde_json::to_string(s) {
                Ok(value) => value,
                Err(e) => return Box::pin(futures::future::err(Error::Serde(e))),
            };
            {{/isArray}}
            req = req.with_query_param("{{{baseName}}}".to_string(), query_value);
        }
        {{/required}}
        {{/queryParams}}
        {{#pathParams}}
        {{#required}}
        {{^isNullable}}
        req = req.with_path_param("{{{baseName}}}".to_string(), {{{paramName}}}{{#isArray}}.join(","){{/isArray}}.to_string());
        {{/isNullable}}
        {{#isNullable}}
        match {{{paramName}}} {
            Some(param_value) => { req = req.with_path_param("{{{baseName}}}".to_string(), param_value{{#isArray}}.join(","){{/isArray}}.to_string()); },
            None => { req = req.with_path_param("{{{baseName}}}".to_string(), "".to_string()); },
        }
        {{/isNullable}}
        {{/required}}
        {{^required}}
        if let Some(param_value) = {{{paramName}}} {
            req = req.with_path_param("{{{baseName}}}".to_string(), param_value{{#isArray}}.join(","){{/isArray}}.to_string());
        }
        {{/required}}
        {{/pathParams}}
        {{#hasHeaderParams}}
        {{#headerParams}}
        {{#required}}
        {{^isNullable}}
        req = req.with_header_param("{{{baseName}}}".to_string(), {{{paramName}}}{{#isArray}}.join(","){{/isArray}}.to_string());
        {{/isNullable}}
        {{#isNullable}}
        match {{{paramName}}} {
            Some(param_value) => { req = req.with_header_param("{{{baseName}}}".to_string(), param_value{{#isArray}}.join(","){{/isArray}}.to_string()); },
            None => { req = req.with_header_param("{{{baseName}}}".to_string(), "".to_string()); },
        }
        {{/isNullable}}
        {{/required}}
        {{^required}}
        if let Some(param_value) = {{{paramName}}} {
            req = req.with_header_param("{{{baseName}}}".to_string(), param_value{{#isArray}}.join(","){{/isArray}}.to_string());
        }
        {{/required}}
        {{/headerParams}}
        {{/hasHeaderParams}}
        {{#hasFormParams}}
        {{#formParams}}
        {{#isFile}}
        {{#required}}
        {{^isNullable}}
        req = req.with_form_param("{{{baseName}}}".to_string(), unimplemented!());
        {{/isNullable}}
        {{#isNullable}}
        match {{{paramName}}} {
            Some(param_value) => { req = req.with_form_param("{{{baseName}}}".to_string(), unimplemented!()); },
            None => { req = req.with_form_param("{{{baseName}}}".to_string(), unimplemented!()); },
        }
        {{/isNullable}}
        {{/required}}
        {{^required}}
        if let Some(param_value) = {{{paramName}}} {
            req = req.with_form_param("{{{baseName}}}".to_string(), unimplemented!());
        }
        {{/required}}
        {{/isFile}}
        {{^isFile}}
        {{#required}}
        {{^isNullable}}
        req = req.with_form_param("{{{baseName}}}".to_string(), {{{paramName}}}{{#isArray}}.join(","){{/isArray}}.to_string());
        {{/isNullable}}
        {{#isNullable}}
        match {{{paramName}}} {
            Some(param_value) => { req = req.with_form_param("{{{baseName}}}".to_string(), param_value{{#isArray}}.join(","){{/isArray}}.to_string()); },
            None => { req = req.with_form_param("{{{baseName}}}".to_string(), "".to_string()); },
        }
        {{/isNullable}}
        {{/required}}
        {{^required}}
        if let Some(param_value) = {{{paramName}}} {
            req = req.with_form_param("{{{baseName}}}".to_string(), param_value{{#isArray}}.join(","){{/isArray}}.to_string());
        }
        {{/required}}
        {{/isFile}}
        {{/formParams}}
        {{/hasFormParams}}
        {{#hasBodyParam}}
        {{#bodyParams}}
        req = req.with_body_param({{{paramName}}});
        {{/bodyParams}}
        {{/hasBodyParam}}
        {{^returnType}}
        req = req.returns_nothing();
        {{/returnType}}

        req.execute(self.configuration.borrow())
    }

{{/operation}}
{{/operations}}
}
